import cv2 as cv
import numpy as np

# -------------------霍夫线检测--------------------
img = cv.imread('line.jpeg')

gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)  # 灰度化
edges = cv.Canny(gray, 50, 150)  # 边缘检测

# 霍夫线检测
#第一个参数：二值化图像，第二个参数：rho的精度（单位是像素，通常为 0.5 到 2.0，rho和theta是极坐标系中两个参数），
# 第三个参数：theta的精度（单位是弧度，np.pi/180表示1度），第四个参数：阈值，通常为 100 到 1000，越大表示检测的线越少
lines = cv.HoughLines(edges, 0.8, np.pi/180, 150) 

# 求出直线的两点坐标，画出检测出的线
for line in lines: # 遍历每一条线
    rho, theta = line[0] # 第一个元素是距离rho，第二个元素是角度theta
    a = np.cos(theta) # 计算角度的cos值
    b = np.sin(theta) # 计算角度的sin值
    x0 = a*rho #线与原点的垂足点横坐标
    y0 = b*rho #线与原点的垂足点纵坐标
    x1 = int(x0 + 1000*(-b)) #这里乘以1000是为了能够让画出来的线横穿整个图像
    y1 = int(y0 + 1000*(a)) #(x1,y1)是直线的起点坐标，(x2,y2)是直线的终点坐标
    x2 = int(x0 - 1000*(-b))
    y2 = int(y0 - 1000*(a))
    cv.line(img, (x1, y1), (x2, y2), (0, 0, 255), 2) # 画出直线

cv.imshow('img', img)
cv.waitKey(0)
cv.destroyAllWindows()

# -------------------霍夫圆检测---------------------------------
planets = cv.imread('circles.png')

gray = cv.cvtColor(planets, cv.COLOR_BGR2GRAY)  # 灰度化

# 中值模糊
img = cv.medianBlur(gray, 7)
# cv.imshow('img', img)
# cv.waitKey(0)

# 霍夫圆检测
circles = cv.HoughCircles(img, cv.HOUGH_GRADIENT, 1, 200, param1=120, param2=30, minRadius=20, maxRadius=300)
# 参数说明：
# 1.图像
# 2.检测方法，这里使用的是霍夫梯度法，目前只有霍夫梯度法一种
# 3.dp，即分辨率，这里设置为1，累加器与输入图像尺寸相同，dp=2时，累加器为输入图像的一半大小，以此类推。
# 4.minDist，即圆心之间的最小距离（单位像素），值过小：会检测到多个相邻的同心圆；值过大：会漏掉一些圆。
# 5.param1，即高阈值，值越大：边缘检测越严格，仅保留明显的边缘值越小：会检测到更多边缘，可能增加误检。通常为50~150
# 6.param2，圆心检测的累加器阈值。值越小，越容易检测到更多的圆；值越大，只保留可信度高的圆。
# 7.minRadius，检测到的圆的最小半径
# 8.maxRadius，检测到的圆的最大半径


# 求出圆的中心坐标和半径，画出检测出的圆
for i in circles[0, :]:
    cv.circle(planets, (int(i[0]), int(i[1])), int(i[2]), (255, 255, 255), 2) # 画出圆边界
    cv.circle(planets, (int(i[0]), int(i[1])), 2, (0, 0, 255), -1) # 画出圆心，第三个参数给2是半径，很小，-1是填充，所以显示出圆心

cv.imshow('img', planets)
cv.waitKey(0)
cv.destroyAllWindows()
    